use core::fmt::Debug;

use alloy_sol_types::SolValue;
use base_light_client_types::{
    ClientStateV1, Header,
    header::{L2Header, OutputRootProof},
};
use evm_storage_verifier::{
    verify_account_code_hash, verify_account_storage_root, verify_storage_proof,
};
use unionlabs::{
    ethereum::{keccak256, slot::Slot},
    primitives::{ByteArrayExt, H160, H256, U256, encoding::HexPrefixed},
};

#[derive(thiserror::Error, Debug, PartialEq, Clone)]
pub enum Error {
    #[error("invalid l2 oracle account proof")]
    InvalidL2OracleAccountProof(#[source] evm_storage_verifier::error::Error),
    #[error("invalid output proposal storage proof")]
    InvalidOutputProposalStorageProof(#[source] evm_storage_verifier::error::Error),
    #[error("output root proof hash mismatch: actual={actual}, expected={expected}")]
    OutputRootHashMismatch { actual: H256, expected: H256 },
    #[error("invalid ibc contract account proof")]
    InvalidIbcContractProof(#[source] evm_storage_verifier::error::Error),
    #[error("invalid game code proof")]
    InvalidGameCodeProof(#[source] evm_storage_verifier::error::Error),
    #[error("invalid code size, expected a minimum of {expected_minimum}, got {actual}")]
    InvalidCodeSize {
        expected_minimum: usize,
        actual: usize,
    },
    #[error("invalid ibc contract account proof")]
    InvalidIbcContractStorageRoot,
    #[error("the l2 header is not finalized")]
    HeaderNotFinalized,
}

pub fn verify_header(
    client_state: &ClientStateV1,
    header: &Header,
    l1_state_root: H256,
) -> Result<(), Error> {
    // 1. Verify that the DisputeGameFactory is member of the L1 root.
    verify_account_storage_root(
        l1_state_root,
        &client_state.dispute_game_factory_address,
        &header.dispute_game_factory_account_proof.proof,
        &header.dispute_game_factory_account_proof.storage_root,
    )
    .map_err(Error::InvalidL2OracleAccountProof)?;

    let game_slot = compute_game_slot(
        client_state.dispute_game_factory_dispute_game_list_slot,
        header.game_index,
    );

    // 2. Verify game is included in the DisputeGameFactory.
    verify_storage_proof(
        header.dispute_game_factory_account_proof.storage_root,
        game_slot,
        &rlp::encode(&header.game_proof.value),
        &header.game_proof.proof,
    )
    .map_err(Error::InvalidOutputProposalStorageProof)?;

    let game_id = header.game_proof.value.to_be_bytes();
    // See https://github.com/ethereum-optimism/optimism/blob/4a7cb8a198a1f027e739d2e51dc170faf02b5d28/packages/contracts-bedrock/src/dispute/lib/LibUDT.sol#L70-L79
    let game_account_address = H160::<HexPrefixed>::new(game_id.array_slice::<12, 20>());
    let game_account_code_hash = keccak256(&header.game_account_code);

    // 3. Verify that the provided code is what's currently backing the game account.
    verify_account_code_hash(
        l1_state_root,
        &game_account_address,
        &header.game_account_proof.proof,
        &game_account_code_hash,
    )
    .map_err(Error::InvalidGameCodeProof)?;

    // 4. Verify that the provided l2 header hash matches the block hash within
    // the output root proof.
    verify_l2_header_is_related_to_output_root_proof(&header.output_root_proof, &header.l2_header)?;

    let minimum_code_size = client_state.fault_dispute_game_code_root_claim_index as usize
        + H256::<HexPrefixed>::BYTES_LEN;
    if header.game_account_code.len() < minimum_code_size {
        return Err(Error::InvalidCodeSize {
            expected_minimum: minimum_code_size,
            actual: header.game_account_code.len(),
        });
    }
    let output_root_proof_hash = compute_output_root_proof_hash(&header.output_root_proof);

    let root_claim_index = client_state.fault_dispute_game_code_root_claim_index;
    let root_claim = H256::<HexPrefixed>::new(
        header.game_account_code
            [root_claim_index as _..root_claim_index as usize + H256::<HexPrefixed>::BYTES_LEN]
            .try_into()
            .expect("impossible"),
    );

    // 5. Verify that the provided output root proof hash matches the stored root claim.
    if root_claim != output_root_proof_hash {
        return Err(Error::OutputRootHashMismatch {
            actual: output_root_proof_hash,
            expected: root_claim,
        });
    }

    // 6. Verify that the ibc account root is part of the L2 root.
    verify_account_storage_root(
        header.l2_header.state_root,
        &client_state.ibc_contract_address,
        &header.l2_ibc_account_proof.proof,
        &header.l2_ibc_account_proof.storage_root,
    )
    .map_err(Error::InvalidIbcContractProof)?;

    Ok(())
}

pub fn compute_game_slot(dispute_game_list_slot: U256, index: U256) -> U256 {
    let offset = Slot::Offset(dispute_game_list_slot);
    Slot::Array(&offset, index).slot()
}

// https://github.com/ethereum-optimism/optimism/blob/99a53381019d3571359d989671ccf70f8d69dfd9/packages/contracts-bedrock/src/libraries/Hashing.sol#L114
pub fn compute_output_root_proof_hash(output_root_proof: &OutputRootProof) -> H256 {
    keccak256(
        (
            output_root_proof.version,
            output_root_proof.state_root,
            output_root_proof.message_passer_storage_root,
            output_root_proof.latest_block_hash,
        )
            .abi_encode_params(),
    )
}

pub fn verify_l2_header_is_related_to_output_root_proof(
    output_root_proof: &OutputRootProof,
    l2_header: &L2Header,
) -> Result<(), Error> {
    let block_hash = l2_header.hash();
    if block_hash == output_root_proof.latest_block_hash {
        Ok(())
    } else {
        Err(Error::OutputRootHashMismatch {
            actual: block_hash,
            expected: output_root_proof.latest_block_hash,
        })
    }
}

#[cfg(test)]
mod tests {
    use base_light_client_types::{ClientStateV1, Header};
    use hex_literal::hex;
    use ibc_union_spec::ClientId;
    use unionlabs::encoding::{DecodeAs, Json};

    use super::*;

    #[test]
    fn test_update() {
        // Test L2 settlement of block 32382316 = 0x1ee1d6c at mainnet block 22839478 = 0x15c80b6, where https://dashboard.tenderly.co/tx/0xddc2095d8d800ddebd22d2717841cb3c7eefa3c76f97316daf6ceb0897a7ab43 happened

        /* The immutable arguments injected by the proxy

        creator: H160 = 0x0,
        root_claim: H256 = 0x14,
        l1_head: H256 = 0x34,
        ...

        Arguments are stored in the bytecode at a specific index (98 for mainnet)

        BYTECODE_OFFSET = START_INDEX + FIELD_OFFSET = 98 + FIELD_OFFSET
         */
        let client_state = ClientStateV1 {
            chain_id: 8453u32.into(),
            latest_height: 0x1ee1d6b,
            l1_client_id: ClientId!(1),
            dispute_game_factory_address: hex!("43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e").into(),
            dispute_game_factory_dispute_game_list_slot: 0x68u32.into(),
            fault_dispute_game_code_root_claim_index: 98 + 20,
            frozen_height: 0,
            ibc_contract_address: hex!("8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2").into(),
        };

        let l1_state_root = H256::new(hex!(
            "93935df7e1bd2aac6702c3da33ab87c02769f44d61db6df3aa1d0aaad9046797"
        ));

        let header = Header::decode_as::<Json>(
            r#"{
    "l1_height": 0,
    "dispute_game_factory_account_proof": {
        "storage_root": "0x4a3dd440909333cf6152ddbc57c2132ad6d208c4b733ddd2c7b9ea940beb46d7",
        "proof": [
    "0xf90211a03c91104da70b0e1eeb67abd7e8518d36bf56d179952fb33ea2ad7fdf5f9116b6a013b68a0b4112d48f61b5cd90415f1ea3921d57ba4dae31fda20ad6449cba0700a0a916c9eb50184ae67fb9845a2695b9ec4ac67bd88ae97af6a54470bed2d2c887a0dda95f02f4c865cb5c2c37510d5f46b8040e4d9b9ad53c57d5b800a67f8ddfdfa0921788dccd210a0da757955539a5b51ee5537a9db2469ba3fc393f88daf11fbba099cd6a675def6c35269f3e8ec780456a21067b4008b8075f481505eeaa6a7ed1a05158229a4d4c8051c604dd0da0e9c7768b70f5171e873a945a8edbbc7db1c46da083724ff8df5d0ee49f5991e7c126f6ecc9322d4bbc8d11730aca324355860462a0d741d54929cdcdda3abf467c2e3b08dce5ec565e6d4da2a8af342031cc7a61d1a08f03fc301d262f0cc9387eac1b9035e3b940aacef2af13024752eb8f7c868744a0832150cd5e5c0cc0351b5441f062f773c2457d68a157d3d8202cb896a4a37d61a0e58dcf99f6e92815d1d50dbb1dc022d848d7bf8bc8ae4d9fce1466b389015f6fa03837212b566eff45697578ee0198944f4f94a88dd817ff57842b4018f045c664a085c35ed3c2b8a6a55d1cc6115ac869401b4a026718d7646d0eb51c24bf44dd71a09a083a9dfe87a6d812b7a7fe671bbd4ce0d227cd152bd4cb6fbb4f7c8f26ba28a0c8ce4383a51219cff18f603ba471a4d9b286a8495895f076d6b8226bbbb18e4880",
    "0xf90211a0ac55518b57c88b1f92614fae32fc4c3dbbc95e34ae48959d23cceddcf1a7e6fda0f18097ca2fc3c359dfb823d7b82968033ac617ed200f91e7e9de994d425eec9da0b9d7db7bd73aa4a5e3913a6c9369ba9e041d72aa68f07ecb5ef8071ddf4cf201a04b45436fd3dce5eae56ef8c1078b0e045d889dddb72b1584a2415d7f6f6c7c72a03f5de9733629e53c35f7b45f3be0f0ae597ff4018347f0caddb84bd220d635fba0bcbe17a3ea5537eada526b59f51a4297c23c8e7bbffd3b7e795d30b66e94bbbaa0fafdd4f88fce1b16ae696c7456e92afd13708ff6f328152b984ad67323c4186fa08617ed6a9123f3fe4fa1faa4418513db8cde1c1e14b88b2f307dd3428cf8ee5ba0294c1ab90d3f867d0b86f78a6776fe3af74d0ef329a66bc4512320c3efa615d8a027cf902b439e5cbee656c4b8f6124891c3b56b2aac21202180eb0183615ed0d2a0f8b39af1ed7615794573cdb8855b2c1c176705f20348520dc08cb20cb2fdec80a04453d3719769bdd77914030f4ef2e952c60d1c03a9660604a540a649c0c4c85aa061840fa37eef04612cf6d948f729ce6b401fb57baa6697afa56419d2d382a5aca083ead3c8a3444bf295e3b0cf28d3f5d41599cf3eaaf87788dd8687d12b86d2bfa0152d5b66e100dc786e8ce7f1a4aee2522b1b0bc643eaa8552a6ef3a57dec8082a09b8e90970168fba73cc23ac34685582c5207b49535e8f66bfa226cbcb31096fb80",
    "0xf90211a0b164e73c7e0f0e5b509ff971a7cb87a7792b550a019e6a98aded5b7dae104c31a08c44c34581641dd4a64c4b6255797d5d622ae34d44afef50ab2c8cad6227f3aba0bdf445f826e3a37c484bd17d1e66aa007554c7acfa3f3ac7f614e3a2ad3a0fb9a09498e1283fb7a4b2031318a93322c245f7f51d4c6daadcf703027e8d43a821dca009df4dbb01de06e6409ea8cb102abc6c29dae6433efa5b36df4e8e7ca369804ca07508cdabde5f9ee8d6d914b2f974fe198b3536cd3f5a5c0bf2b0200bdd05d792a000d64e22ee2f306ad629ffaf0413aeb07fb1402b79fdcb1ae45aba5716657f2ea07bca44c5218e15e72c36be3bb95d1ac0263a46cdcd81fe8c4d430917f7e68b64a0e847cb287d310b26efb299a45f28d2f6489e4a62e53dd789b47f13d537605dc4a0aa93c491fcee9a56f7225983b92289c77bc312bddcd727ad9f430427aa1c73caa072933daade13cf017e52de3db203e2507c34e9c62ecb73c02a9e6f0d4d60e954a0944d348ac2c5704b1cc34085f9b07a3649d75e655e36f42006ffa902d55f5162a090ff6a8826d83f6ea429161f816c99f680926192678d7254d741de9441b32fbda0e5888cc3a1608af53596fdba08a7116d7acc9b03757819834041f2081609a0e6a0e8bc1def5752ab41ff5e82898c2c940c46a5349cd512afe74659da76c608cb7da031a5ab2b899f49156c776a1dab1dfb2d088354c9a94c188ed3e1bccf3c78429b80",
    "0xf90211a05648d994634405e4337d3f4ed058051e30018066a5f282069ed56044b0b25e73a0ce162dd3b89abbe9e5a438d1a4e14173825543749b9247e11ab1c5003b23b0f7a039fa73bd5cb1588eb22ba27dcc990f03e2c8f422a4f73e055903f20bab1f1ceaa09be65355e62099e0f87a23f314606d80a0e5665e37eda0ad873dddf79098342da0676f083bc13e85c444f38dcb4c85ee94d922b7e0915b5d8268e2676c394a7429a0ff1da0b0a42c7b23b5fe72269520ba0e659560af882d91bb1bd0cfe40ff308f0a04804e9ef2aed6f6c311f2ba227e06a1683ea84d0ee9344abbc1bf2285f118ab5a0f04698f834e0cddfc61428761d98730858ed8ec5a54bc7ad80c96defe0b00b68a0fd9522a40a8dd42123751536735ebc6d04e0c94db350eec5687f032fbdc736b3a0e28514fdd5b06cafe023778d2c750069d3c09b12a91532e9b77ed82ba72bd13ba00aeaa16474db3b39366d5b769347f4bfbaaef6ebbd980617ad5fab398e5e9ae5a03821271eb5d2bd0a7e50be0d19357811574681ffead8f6953207e0c2b03c2988a011db887c308071849c87d0dd76f49123d3f152927c5b1fb751770658b8e034f0a07ce475cf87bd696564ea40d644818a5fb980d2b9d8fae7c030c5fa747c89d69da079f18d232e4d4b01c7716a3b260a94ae14693f850a26e7aaa35e429899e3b3d5a083938c46c138f0a73c50519acd9cafdcce148d0b3a4e8d86411b077a0a4c23fd80",
    "0xf90211a090c6d51d3d9a11156912322b8a8592c22468cb43da92d10d5605538794f35010a09d299193d3b37bd1984ff4a6519f6689cf422bae4ab4ee4e843b1bda6e48f3a8a0991497eece7b346fb88266fd49079c26110620632a066f328bdfd2eb1c2a9389a01b1ed89e1929ba60b53ffa15f807daa414fd5a8615c20c99fd6a6ae6950c20d7a0c9108808793c0cdaac72ff65be3fbd7cf7f2f1751cb6b965c762eed1e248f42ea0cdd44467853c4cd68a74b6af3a07715ac40c6a418d64465cade4941cd28ed174a0271b564982fc367a0050adf1ce0fc61ef32fd2d490d9b40881019b6161146df5a0e21c2cb49903c2a16427ad577c272d10c4eef4a12df75ef33b0f016b49349969a09ae48f37349b0e3144963a5112f1ac0c0fcb473ba3d00424b99b19e9f3809e2aa026892ea1685ad307a8c5c09876b00ade72fa47ad822a42a0a51a280e505f9ea2a0cabb359220ec487ac768daf13ed7374355cbb8c081f8538f037f51c1b6961484a02e5b83571806ca085c581caa03ed9bd0f40f9fb32bd5d9dd4679165f8e0fb1b6a06d54d287055133e81f9db5aa1ed4f7f64eeb2da4acdb0b49c12ac8b2d1cde980a04ac9c6aebd2fc6fbd96abb3411f7cb3019cdd3177578c3bb34fd6993b97a5251a06c309af45a6ee51f81cce51428f5678ed72efb596f85a520fc12b1e5cd9adc4da02c6d0803a4b904ee9b1bfa3f404bdea4c065ae5447938f88ecf70afa2942c3cc80",
    "0xf90211a0edf31d020b2ae0c4bb99843c61e9632e8e4969c1b01432360b63a5a284a83220a032de3a184ae122a01373fe2d10914199968d8895b769edc5e6ce89e49f3eb3a0a0ae9a87cdd69cd00e8aa26c128fe00080a68187e93eb4e14a658db871606ba2c6a01815ade0e993e4d0caf95657bfd0569e5842c9e2324cac1236a4bb01b74a0b3fa096afc666c3a82acc0bc245bb8821cdb33f8b3723a9158caf309604ef7251d7bea0cb6649e8fd23736ab1155bdf1d88412524068f84565cae8b72c886a223088f8aa0ea2d8998aee5a88ba29c78561d4c5326a3bb338c0a82e02857c4d9e3831618daa0f1cc4d93a0ad373261a451fad2c50dc9b1e45d9d1d49d07fdc6ca8fec88f3fd5a0f2efe7ddb1d6224f980cb78a8daaf0417d8b160dfea527d3bcb70fa5548b6344a049a8abd3181857b752c286b20fb54eeb2f7d73dd02551bf3f21a7e064245d494a041b0609d93378e324793726f8d326a443f65d5977af76d96d8a3002af0bbc3e2a0bdf6b7f036110a7d9c649685286547d2d772cd64c6f5ca9f274828943786f071a0e10e4dc4070ddf6de95648cde9f9ac506fa9b604b1d43ad8a9143e4caf9286d6a006de4a0e24cc3ca63ca71c1e6e046e9a2b0eaf0c161fd790bd9d91233fd6bb95a0ff33bf0dc7412ecc7c238d387b68643793cf99b5a44b7c560e4512de8dfb2d8aa09c5c42af93d8b3b31f11a9c0643a4ce6bc90b7b46bfcd6e5c5abe62298eefdbd80",
    "0xf90171a0b0a7bf3e472eb8aba4a4e0cb8e7b3faf0d3ebace64722b74649a843cd50910a5a0d6fadd51a45214097127fe5360631672d32ab8f433e240fd0ffdfe363a8870b7a0b5e9e9b355f4fab25a2ee207185bc2639456052f6a6a6b2340520b9942456837a01fb9224a229669aeeaf9caa629ecaf7428a1fb2fbf029d081aa8d5de19ee9a4ea07165a2a87e365dbfae69495ebfe650b89d299fddcf1459bc402d2c267f228e0c80a03862683cff0896d1dec4fd7ae3693a81eaa8c67fe7b8a9f44a73b4eb395074f6a09ff044c866d7815c47736c78597248441c21603b1a5ef71a8dffd509603859b180a0c66476db1ea874e5a8f252357601c6583852f4d59cb1d46766c5c2e8f5a291b380a005d0ee378211f10c970b9ce5a499cafe69bb776997d15acbbef819a211684c7ea0d9d9da96a375658115ce1ef325996d681d7aebd5fbbf6cdac19058da0598404ca031010bfe5e92d7b4719a9f2dc2768e1a2e7a3d6323307627670a113b22a82f44808080",
    "0xf8518080808080a040c49aeed5a3274ec17df4ee5939fe2ea0555865f45cbf007d55401e2dde6af8808080808080a0fcba562f4a425a0dc945033705213a0bf7c1e4099f23c65f51c5226961d6fc6b80808080",
    "0xf8689d200466aed0bf0380fd585c5f3145d455cceea4f6693372e79e183b567ab848f8468216f880a04a3dd440909333cf6152ddbc57c2132ad6d208c4b733ddd2c7b9ea940beb46d7a0fa8c9db6c6cab7108dea276f4cd09d575674eb0852c0fa3187e59e98ef977998"
        ]
    },
    "game_index": "5878",
    "game_proof": {
      "key": "73312145035153491510562152807817059592623112619519005820720798265374763748937",
      "value": "2559900716436491591336555206044410792524573524856380146979",
      "proof": [
        "0xf90211a07738a4d99ab4a4b9955d369cfcf66c77b3c5ff6e1ec9a57fac393276d4a4b12fa0d37cd712951e2bcf9e3449d932c4ba2cfeb28405f3b8afe70bf7f1d134fe2fe1a0a6dd37f0dde817873d1e7e74be29b374d529cce3df000ba81bdab960954e4409a0ba3678b8016b0562df6ce56fdbc5dd56647732416d855bb5f13e19b356a9c3dca0082013320ce29a388809bc9d2d15761b01e5c2aa02a98f19bfb3dd29dd928949a01ea908f5803f2eb4fb95034310d32f12cb523be09d7748ca3c2a40424ef47d9ca0c73c777f8d95c9bf7fabc3048b56fe172b1c8769acabe4bd3d4475c8204ae301a013b314cf3e362fd7e43281f8bb718a31433f31e0ecd6f0be0e6553a9f151584fa0498b398296e10e3b6a416a445937b80806072cf90bebe9d7c621266af945bc12a050ccbe46e29db6f357efea71be575161276d43f4f08d3ee1db1dc0fda995c731a0cc28da2ffdba31a3651e74fa64ac00d15ebadb2b59adf5c15068c64dca0c0b7ba0192b5ef3ac3222a74ee2aec8727fc38359c0466ea402ddd9fcc7f8b34f40708ba0a2f9add99341eed7d2beb5b0c3385b1f7d8d1f80460584e8ff71ff2c943ef31ea0cd38fc92b5a1cc1d535c1db6b73e6625298db29e98b4aa8b8e0bd563e318b5b0a030574d141a9b073c72aea5fb7b77501ad6609d79db1075ec8503c83e39cba6daa02c8fe13d2b9be1b4a5665d4000e4a883602302e1b50f7a78e4962c4dfb0dbfd280",
        "0xf90211a0b68163a4f440faa4ff5c53b8533134465b0390e77bb4a5c2777aea52f3b3b14da0c041e5dc81aee5ae94338ecc471d9774f821b011b7c0e841c57634b9c8a7077ca04d8aa71af31bb6164a38f425cb278a2b214f538e2e7f7fa4056d63e84327ad7ba0459636976bcd6cea3d563d6b2c9a1542f797d6ce2c31cf5ad2960f9acfd2393da0e5f0fffdabb5996d5689c5462b5a8d048980bd9d9ae3c99ca33a8dfd7e0026fda04c71bf13e0e47cf39e220ad0421c180b7ed9381eef233fb7c8f7de57454804bca04e520a68aa33bd824bae8269d9548678998c973b53297ef1562a8637f6d2dec9a0ace35bde7e50f099b097c6f62b9cda174633e28ce2ea564fed4a0d7b789d7793a020e0ca5109565e41c6313f1f1409a70590cf1be7fd6be24b907be158dd4a11dca0e985bf3d48e85069613a62cfb765afe9630cc243a6efd9a0992f645809157eeca0964b48b4a5bf60a4163b8582afb63850cb4b1431666aaa8a91b52a6d3d43c629a0610b9d5f4443bca5051eea84b4d459a446ff75c3575d245b35b58a4ec785f290a01dab0011fd5427a910f5d981e19818dcacd11e97db27d1c2d2b7f3efde988e8fa021a01063d0c680489dccd3522c8de35704b4a037941548dc09f3e20c27ae42c9a0622cf93b78d54944b38f45cd5a88831eff7ea52e2632b0ce0da4d2570286e493a020bc6b2d6b7e42df644959a84fe334943eed8b24f09a06954577e879e27ef27580",
        "0xf90211a0e952aa47b503c979df464f3fcc917c6c8ac5da97c510a3e9153915fdace03ecaa0bc35fcfdb52d7b382d4db25843a28fce6ce0a50665a64b82e0e949e7778c6787a063633a8e5aac07d0a1340b9525279eddc0718a49049ea9b4f6996723ab0f8f4da0a7ff9aae8a296684bd68aacd26f8f79915aa30fcd44a387f67e0102a94c41837a0378604072efabe72ff3bc26b8c0038a0dd79915f62f2c1ffcc65dfa4567de809a0399f8a0754f717aa8fa13236f00672461b93c667d40110748daca9fb5eb22c87a0dc125dcb0052c611b6723c86da451419faf5985a9490b3d3b58f95a659dfb620a06b32ab0fb8755d2f2330944d2018a183356842118fb06b6f7c87fc7531493a89a0e404ddf701bdfcce5497c3c9ef2544396cb53bc59c4abcbf48dccf5d311a4311a0617552c41399b9409cd1ab9b1714de7cd011f324abf6a8b49c47e0330d12e601a0e8433b38067e4a179f2576fbdbfab56212f60580cf5f3dd7607094e624e54015a0c6f8de98f10fd79157ecebe2e9e23f2189c33d94c62796937cf71540abea0fdfa0275b6013caadf613633c7ee42a13513211d6a8f00d339342f7d04254d2ed5230a01651967d3fe6b79cc34a12374d0f5d7ee0dc02e57b20ece582845cad7144b656a09ff2c0fe38c5a8ae65b625dd402d81991f9b2b4efbed320f8a5493325fdbd206a0d34d20bf6d83b5c7bc53c955228607d7f4f0ca6734e8f780124d59d2947158b180",
        "0xf89180a0d09350dc3d8e4b6c33193e328311dc946492247c0828ecb2006402cabdcaf0b48080a09757a2f033a392bd2b18338b1b11f25534ca00fb6e3142cd83fbc8e12ca5134480808080a05a42d8ebe7860bd61750a37e1b408d58b033687c9e74a0eec438ad00ab22629d80808080a0325dcba6dea3b1045d5e0b7914eaaaabfea6f30b0822e99f063b77025a21d8a08080",
        "0xf83a9f20414da8d01851cfeddc3eebc0c5be72526516f223c110e722531baa1549e2999868669c4bd5ce8cae82eda8322d3b7e32396f786e10154523"
      ]
    },
    "game_account_code": "0x36602c57343d527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff593da1005b363d3d373d3d3d3d610076806062363936013d73ab91fb6cef84199145133f75cbd96b8a31f184ed5af43d3d93803e606057fd5bf3642229f238fb9de03374be34b0ed8d9de80752c5cbe0e4c5659eb151aca2d5c56444e936ea6d1786f990c3fe34aaba20710e2c2b246783f147529df3992748841f67cbbab863d5f723ea54b2e17849cc6a42743d0000000000000000000000000000000000000000000000000000000001ee1d6c0076",
    "game_account_proof": {
        "storage_root": "0x478630675576d2e16a8b52a5f70ece26ae27dae4eb1a807a5c6fbf507d040ea3",
        "proof": [
"0xf90211a03c91104da70b0e1eeb67abd7e8518d36bf56d179952fb33ea2ad7fdf5f9116b6a013b68a0b4112d48f61b5cd90415f1ea3921d57ba4dae31fda20ad6449cba0700a0a916c9eb50184ae67fb9845a2695b9ec4ac67bd88ae97af6a54470bed2d2c887a0dda95f02f4c865cb5c2c37510d5f46b8040e4d9b9ad53c57d5b800a67f8ddfdfa0921788dccd210a0da757955539a5b51ee5537a9db2469ba3fc393f88daf11fbba099cd6a675def6c35269f3e8ec780456a21067b4008b8075f481505eeaa6a7ed1a05158229a4d4c8051c604dd0da0e9c7768b70f5171e873a945a8edbbc7db1c46da083724ff8df5d0ee49f5991e7c126f6ecc9322d4bbc8d11730aca324355860462a0d741d54929cdcdda3abf467c2e3b08dce5ec565e6d4da2a8af342031cc7a61d1a08f03fc301d262f0cc9387eac1b9035e3b940aacef2af13024752eb8f7c868744a0832150cd5e5c0cc0351b5441f062f773c2457d68a157d3d8202cb896a4a37d61a0e58dcf99f6e92815d1d50dbb1dc022d848d7bf8bc8ae4d9fce1466b389015f6fa03837212b566eff45697578ee0198944f4f94a88dd817ff57842b4018f045c664a085c35ed3c2b8a6a55d1cc6115ac869401b4a026718d7646d0eb51c24bf44dd71a09a083a9dfe87a6d812b7a7fe671bbd4ce0d227cd152bd4cb6fbb4f7c8f26ba28a0c8ce4383a51219cff18f603ba471a4d9b286a8495895f076d6b8226bbbb18e4880",
    "0xf90211a0d2853228101fb77157d52ecdef2ec422ea965176a7a2f02a18869f2049610731a03d5fb6470767e956b4ab23580dfa6d1050bb8e1f2d23d8877d2ecb8a30bb88b7a0a4cf6ae2145e0dd1aa751214c47d22f0b6d0f784013e1a3a38c93215baa7d4c3a07bb08b66547c915bea5abdd3e78f89295e9b72a60e5b38197c5e9f6cb7c4456fa031835eea9355ab5bfae1afbcd6e459b1d65fee6b4b6393e5bec8185bbac083f7a09eb8d0ff2e38a57390fdb0c4f39b9f23549189a8fae783ac36296cb5cc50b8c7a03c73ba49d240a3c726044766f423d14c9885f10acf3760f8a4ecda064f0c8efca0385957ad810a8ac6403b47106590eb446456a4d4b61e599258274dfa380709c7a01f7e581325ef1ca3bd52c79249a7f4839fb332f015fd7b0bc940a1840e76c5d0a0ca7238a88b8354e6c942c01c54858d1876a1a7073f5b15f8e70d06290024b0faa0f9ec6a316cad66f5db86147aae1d71b80fba065a9abfa6ec3e7adb8bb23e37c3a037908e259e772f48769173e45459cf4fea21c84815343d7df911c46173ec855da06b0991f339458dbf9c45dc0dd3b23cc72c197cb950e1a75d40fc605c801c614da0c7eee2b903cc4f297ab3b20379ff9ae888e21e24c0a4a3cbceb334f662ba25cfa030fa5f856a8b18a81202ca000c297d3673ffafccb46a2b18d7f3c26bcbdb8e58a0da6448aa9ed5724afb700282aa5a0bbc4453ea49b4403dab09ceff70da91788580",
    "0xf90211a08a87c11b9d38d1fe54456806e73308335e3ec9acaa7af7dd75f21b7f9b26e864a0e779108a4f63faa6d6b976af0749a6627aeb5a1480a022c5c862931f502abdb7a02761fe72dcce8a5d95fa377603138e42a8dc969e47a7b097ad70832e18cc64d7a015d7dcf569d95e24478070b5596ec98cac8777732319f64d9d0a2c8e0c3db709a09446c94b52da0d12072031705d94ccff0da0287f82228896a35348fdb7c55c57a05f01faf1a616d31a6099ed5a3584d851a910562504d799f3355d6079fc3f32f5a0daeceadec89f469468fd348f688480797beb94658b922959bb75d5f5f0265375a02f279f456fd365b6499c98b60d2e3e5a79b76494d7d5df360763a3d58a0f2535a0898f3c598a433717f82e0438fd0cf9a2da4dd9ec7c158109cae974074eeff3a4a0a6e8658e6bd5104e86202c68dda6f64089a0e97829fcdf2e13a27946b01a6c6ea01c90a9b3a63b1bf26b5f010f6751d7004106274c19be3d47539c26a38f15146fa0b2ea8de963ad4dbe51914dd070325737367c936fbbe284cb764ea76f9d95daf9a0ae21ff699e9797c240cc2b8e3e73008ee31425813a054bf4a005821440d0bcfba04597012f69745d0af772fc56468f98e65044ed89e7d4d91cc5c5cf6a5ddacdd2a0950cef8035475bce88ad73a825ab7ad21a0e36b1ff03377e4b71f9e00b6116c1a08465b18cbba3ea985e93f855b9a29ac29442a8f19cd2cb3455cbf28c5ff4850180",
    "0xf90211a0530ad12feb5b25a64d83f99034614b4de89363a180bd261843b3912e9631cccaa0e8d18a88d2f93354a039cc3fdd5fe0386d2f1ba97418ed52af8af2eff5575135a0629257b68f6ed0c2aa9c3a53ba6e077346a590e386e47e5a10aa7c5d4ec4ed34a06d14db297ba27adf8c79810f20d4a0c708afcc9601e440348efe413712b69abfa0b607b6c08b2db16080442f64dc8ca9bc4d51f7b50962574849d82a913073b651a0d5ca936012459b387099947a510e367bff793348b7ba63f0c753fed5171b1128a02798c64926046e10b471faaa5a0e196937b2793091a7b9e1c1bb19aa84bef860a0e096a6c998a08a71ef0d8524bd696777fd639b095b78004f9a8dd8f69d358062a0c16e4438601600263b0f8b930773912994305ab3afd9628dc83adc09a383c974a015abadb220196dd2bc3390dd52f2d4d8562e3b605a5cd2faa259e5c0e34b0765a09c0aa78bb1b082ebd9657e68530ee526b3c413b5dde3f3918eee89db49b434c3a0bae8159f53f4dc98fbcf29b440cf8b237c65eac97701efb5084ef3e28e214f27a0dc6e90ce23c56c802dbf335a3891a7959d2d989c8b4244b904ddbe6b0924a133a0734cdc9c21b99dad675f77cfa307b6ed5400f1a3d3ff65cd093a44e10a5bd540a014ea6b5be04c6598567ae9ba19f5e92a916092c187d4190b58c8ae317a75c3b3a07027dd05552047086ae3c1cf8f5217f1fcc36f7b93975550ef4a01d243c02b4d80",
    "0xf90211a07e73a334781aca9680d9c963470747df52fa1a71a21086f8046e2f1a4e729a0da082e96ca9e877af0914083134b10efd966ea7aa7fcd490d806612103498fd88dea0310c5705de622da9eb51f563c7f578411947fdf0087239ac3201196ad66eea92a0945e284350f16e96a9e96bfef78fd4c811540ea7f9d14b5fefc2e98c11060caca07b3f59e19cd0a8af66f922e0a6f4cd21e1a0f6285f942adbc7e3d6402e08763fa01e7f94c850b31da2424eda009b0e6113f0a59a45b17c89199a79ebb0654671faa06baaafa2f75a44d294b692895299d62fc252bc71d650d964aec94604ec5e38b2a016fba067d1784ecf51167c5d9987f1cbaa3fa49439acff4de4480a8b474f365da0d8d8b9012d6008dc6a9381dbf8ac3e59e4a8f7c894df604db00e27a3b6476d58a03deb50746ae1355772dae16e5ec9372f1c1c040e5c21613dfa9804eb11e77229a0767b1c35351786c48cd076b44a50b9baa052bd309c8bb0995418fdcc78609420a09d4a45cafe9a2aa1716939a9a929ea0f132e9391d1f93a4773518cbeeec522f8a0aafbeea462e2fbcac885a2d1a58198c0c8e42498debd4c45c056d071ac2a2ae1a0ea42e1da68d0dfe7ff87a5542460c236de60fa466f98654ae18fe2dd62add2c5a086d0cfb2700271952663a8c333f7ee7eafbfeae28ecca29babbde229aa14b0eea0263ae79f7a84c3a9d48d8d857ad8651cd17f3c5fd35a4b51c38eefc024b7e5ad80",
    "0xf90211a0c42b45f4ea3c16dea62ed443c29254092af4506d821d78edbd9b18a57bb64432a0f5112587bf76454c537f25433acfc8792bce239be0512102701d3d7b9a58900fa0ef5cae83ee3c2c165f5f6f5d55c8f387bb78d5ed9d090df0c2ba9009d0aa0bc2a0922aa22369fba7f0b63575610c7bb203628a882a3ae0a6506c0abd51bcf4e7a8a06d6a9daf78ccd95181b81a5130cd3951f68aca3f2faada23bdc6bd818f57058fa0cd7d83e0b22a65febdc7716544e3f698bf665be8c80b049cc5ee3ef2c8f05bfea0c5f3930e9c9730209541cbfdc66d5c0bd9c491e47da28c846f19454f39eab894a0105f0d87905ab486e723d7e68d0de7b244e0b120587ca9b4d4aa876e4dd859bda02d5166ef90407beb15665cb9628dc861173074d39d0760f870f175b7026e9854a07c62bb3856ced6acf0cb6e5b6dfe2b3eb10a7a06d4685590feadd164e4e2e44aa04fe747592c37a110da49e5ecc8bb26c3ad31aa082631a6faab6056c0efb7164ba07dc40780b6fe1f8031eb6c65432515d50ffe045a34a5588b0296410956b7d8a4a0f2eff7b9f91999f9662818e8262717aaa35f642d1034f6a635f8005c76ed6d98a0d0383a8aacbdd79fa93f8b3ec1556703fb35a43a17312a8dd0315a8ce007a820a04a46985ff8f771f2a94942d1b22662e9a4ea7e42fb366b971c21a663d70fcb79a0ed101c25722db3247e28794cd5f769449d0de606f9b403207b18180fe2fff34c80",
    "0xf90171a03c86a888b34fda0b8d7c9c19a06e5e71dab7905e03e809a62b4b676192214e67a076147320fd9a39e9ac3dca27502e041caf28a58aa59d968412f40c4f0087986aa050fd096e01a9f8cf9d6a98b2704d0d978105482cb9f1f2825a11d4a3b1465475a0e4820d4eb89af324fc4750edd687517fc9cfdfc3fbcde8478a79805345f4922e80a0510ca1fdc062fa2c80bd8e3b4212a2a8d8d030e3b002209891fdb8601a01b4c680a0eaee68064f947a3a225dff017813cc1f51467bb5d3f68f32e700fa2dfdbc712ea0ad091b27f0244dce5433c4de2fe9241eeeafa878a735add33531589a42619bdb80a0c3f82bcb9a54ce918f5e0922585dafd729f8f913f90938e76a9ef6ef2b8c685aa0bbaf7ab236fd774bb1b894e776367d7a128695bc03390b9c185b010ccb03304fa0bcd52fbd85b2fc0450f697f0168a942d90c1c3674444c2b35fbae619349f844480a045487e914daf5f3c72f9b04c2be894354d61ea54643f86ec025a85f5e80d23148080",
    "0xf87180808080a0e789d8518a53f5d0e3bbe9e0db4761cdfbae7e26124985308fc41eb5af4e14a48080a0d31caf264c715a6296074770dfa44de9243db238a93b0c33fd898d5343619a2a80a0957a624492df7e9a5566e6605c2b777c0ee2a673718062f6049dbf00f5de4b9380808080808080",
    "0xf8669d2035367e3450fe499d4eb2fdd5378f7cd197427f4ff5149a4cfdd13351b846f8440180a09473f62ee32b6497cdc4eb1cad96910b1ee4dcf9851f8252dc8bae08f6b1a195a06b72d24dc5dc210dfeb74a79a13db1c0c0e223dfae6d004e3ba41c5d55ea4814"
        ]
    },
    "l2_ibc_account_proof": {
        "storage_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
        "proof": [
    "0xf90211a0a5749444afb9de0719b3c25f78bce273b9d64af541c6ed7672eddeb1444c4e15a06bfe49566316d5e96a1fcb41529f1f77892d11d45218788a4fe2830b08b0a3e6a0292a0aa9f23fa292fa6954cdccdfe5bb892a2c5dd48f8f43d2577b66ab7a4092a0466ad4f59405fe329dd7ffba77c8ca259dd7aae48120a4b57dee6b726ab32d2ba038c8e5ecbc14f4dc7b3f889eccc8e57530075ca36eb1616bc2947bbb24be78eca0ceb60b8d8102c5f099a15e136b20ed9b95953ef2333856d8ec8b68014e12c521a08fc6726c8cdb3ed904552192a7b9ee44fb707405b9fafb999e7d26a888e4abfda0647098d05ad437a4c7cea38b298605290b275e843096601b5e7d593a00a25949a0ceca2aeb44bdaca9cd11247e412983762ba8f5e464eb1c3f6128560193856503a081a3f4f0532ba6ea28726ce7efb3a429fcd4e8fffe8cf12510420bb12d733e6fa060e1620272bebbf47440beba480477553c521e3d5c049f692834bd333e422b5ba06abc2842c6f01f8b53cec6354d07a7891dcf13179486b036b68cc82b04f6f15fa06e05880d430d6dc74b9ce07253e7d7f699c922fd9da93d659acae40b8ba872e2a0794bd467400be597e9c942ed6d4fa39da59acb231f80951e8f79866b53cafbdda07ba4684fc44dd97e9c5ea6b4f39dc82ce6f06a1d55a4f27d49f6d1a6766590fca0175c9f560776618082df29f56e5e7fb3fda8df4bded32eb521ace4d6e740de9680",
    "0xf90211a078eec529d1b2208512eb2c9c111ecf97f961eea353fe98da5435ff791cc2d6e1a05f3f080422e0f30e8d1985ec779683d671679160ed52e809140e29ae79c16793a0e846b8202e0a52de5b0e99056cd3e9d9d3cc61fbc2b060ea6b388d3f65c71737a0608f5d44476543708ef3fca66cf0d1c522a7e06beac78c64437ee3ec177ee138a097f4cfe17efa339e8fae3088d8171090331d2092ec8a9c69f9ffb0e8817eb442a07b3eebe5c044d49085ca13f9dc7ad08192e0ccd4f3a856ddcde2a766f0c02294a0d7f969f274719a562386752ed80d03f7d806026d3f7ca034f5ef4a4e5532fc83a0330d70dc8543a18776dd3e20ab9d2ce12b12ae9466f41f0801f1743704b95f77a025af5f5ad0000090d49762970a6831d5512589d5fc72cabc8bdf860fbc3e529ea09adea5c2c3391cc5bfa09d1a152c430c750e49589e4fbeae0097fa40240d45e5a027bd5d636a691ba29773558ed87b69758cb3254a21f1a0aed4f94cecb0b30d7ca0a02d94b8e4bcca87766e5a94e043b90f4d825078aecf57c5db6b5a616804d088a03947cc7cc4152dd11005d12e4de94cf97080007e5a8fc86b877653cfe2967699a02b84b6260bc73d47143b4e07b0a949e8df1d0c4ee1e609d8abaa897d037e2f8fa064d63d8d15cf7eba08dfe712561b7adc1fece87c2f001154f7aa6a1fc104061fa083f686abc536d11e44a1ecd9df21aef282235cf604a65d95f96616423576af1780",
    "0xf90211a07d71a00035dce53a845135290988478dc805840ee906511b9e235d03369559aca0f0fae8f5d13934a2dfd0baed90c5b84dc213d20eee5aff2c1346f48c956b7b72a04e61730d43049bf71e06ef415290f7a07ef1327d1fa310d20d91abff94f2a555a02fabdb088366d8a5b56e5da769093b4bf5fc94def5c3ddfcdef7c0fa2c9c722da0d5ebd355c3de38432afc7d5558eca5a5547725c2111145026872f395659866dba08b76071ba768c65c0a3506fba8c8306217a612f8052f1a05c49f6a72b43a0f98a09e0e791b18459f1fde5f6e52217c259fe37da6e7ec807ca4ff3b192e5e16617fa04b2c3fc9c593619f4e6d50997200a919f0b618d30dae9129366dd3b553838dcfa0871be6216a673ac7030866f6a63cc4daea23e4c4066c0b0093ca370101e74a02a08e69adfeb0478637520ff3c06c7847ed3fe97ab0edb135e89c1a9c3d448bbaaca0e7957c0ec6b6f842fc0e567da18cc1d2961515a50e718b17de844ce5043b0744a0d4846d06fa0e967d7938b66255d2905c6960e92f0f03539093a71299fdd49537a06ef13bc3b14039011985d5e25d7902e5707956d530ddf638f2b1f6d58c292bb8a0a5dc9dab0d7912676f6407e955ee32b36809be71fe524914bc50e4ca2b413382a0ac104560ba144d8f241244dc5eec1c8935e95748d2c5ea316663b66fc00c299aa08aa88ad42aa1a53ad427a05d2b5ec8512529887947381c6822eed1579c07d2fe80",
    "0xf90211a080c65aa814be54fa926906fe405068691f10108774e7b2de1278741baeb0ee91a0b71efa83077383f11c88c27d87d9f24168104b40af04ea7adcae6a8e40642caba0a7acfeae74a4bc3686bb958039d47516f769b9dea2139eb9c7f0b0171aaddf4ca08baeb02ac099eb23cd215bc55b9752dc5997f65b2625f07d40582e6ebf57ecdaa0fe02eab0733e182ecb8a5bba724e54959e46bc2d5c6902e6d10652ce018544fba0976cc3e9c01e7f65dea80db21c8803f7744a11f5d50c1288f069845ada032288a0a90fec8fe5ecb05a94521343e9196460a7bff1a4d3f28bb9706416e53c671ecba01ee2d57d6007dfd51c7a64ef06de59fb3d2456e83ed648dd987c0c9d29d11abfa078d9cdbf368d497d7585750ef9a64bdebe51ede6179392409afdf91eeb261679a0bc74d8adff6b37209fcb3848ebd12fdb106da5fe2c7afd29a48830f194b43088a0ea9caa60250da13732a748a45ca4036094517f9f6d0efdd3308dedd822dfb8a9a009df1b7a8cea2186146fa40247a18ed045df1f25d78a66f65538bfe8c14c65e5a01f2def70b64817ad12c53378ef4d6e11f3cfe3e8718efa8bb71c6bb0177d2307a07ece3707e58ed6f331f75ab847b73f6e76db7448ea54f984c19f4a769c4956f0a0892f3d306545ec620d3a5399c426f6baa6dd99966869c42a528d738bfd41a4d0a0ef50b8208a8b1a03d80adf5692c0b38627f7897bfab015ee9c1b0fe4fabca1d380",
    "0xf90211a0b1b0eff8fa5411d0f31da0b710cdcebbaa34057eba84906d9acc5a97fe58dd12a06d2dd42c5ac96dc2ba6c15c170c46d1b3b1654419bab500149f66bcdd5e04391a07729b340f111673c16096842d51b5ee33b59351b8469e59c89c96e379e5b9398a0d0c81f30e803e9e645543ee1f843c66fde2581c42ab1350c41b6a83a5f06e957a01c46e6fa89f28d091e7200d3eaf8d15564ff8c2cb7d4d1ce7637a4a3107c9807a055b384f490503197a56c2682aa7f7f48f1f0a12e8a41673be7eff03e319cfb05a03e9fe8fbf6c79fbca5fbdf37a4129e94ff52e9d1ec4e2f35ea2bb9a10430788ba027a49ae7eacf59fb986bf45087b13faa9e5a11e7ef4c985f5b8128f04b9ebc3aa01d163c4ed679df064464092337b84563587b5e4dc8b06bbba45dca6a7c4d8028a0862ba7b337e9da6ef1d3cdc64b9d881ebc1a13cfab84f1b169eebda0465263f2a0a02cfe5288684a5783f4a040e094139c00baff754efe3689d723c4950d1e0b2ea07a946145653afcbaa1eedd7ddbbeb1905a7065a25ff75bfb4ff532662756fe77a018e9e11902558fabe62e225c09f94515f83992339e38a48bbd3d1a942b018ef5a0b792841c54776cae057e10f223d596c4979610fe7b1d888f1a9d303404314ddea0d53d13e611cea0591a27a58ff1c9cc0d689556f68afd210f0f919bc32df37d09a0bbdb0f1c0321e0708cb3712a6d69af51125159b42e1cefcbb77ed5abd9b5b58a80",
    "0xf90211a0a3c6c138c5213f34184651531459f8f88dba06230a496b837372157bab6d294fa0957d97340f55d8d71f6f9b51107a86282e8ee850d72fdaa932f38acdfe1bcbb9a0c81ae1e63fd6a63cbcabaef67ff6351f964f9fc642447ed5098b669263a1d25ca0d86100d9d13796fe498b50bd88cfc2009e4f2c7801c76a38e03099e6215031f0a0bf955c168e9f96cd1293c3988f24c53da186105f254eb59dc8dca5b6f3e610c5a0a844a67e07c2b359687fb2fa89e112d1a26e62a97faa8b4b8d49d9fd6cc521d8a0abdc1b265e4cf5be7bfdb5dd4b81c4e17e1a407dd1a3d841883a354f18807451a039c4edc5b580df0815cd303accf3028c9881a52eb0eadcc1ea8321cf73b46d28a0725d0278cafff7991596940641e7e9742ddfebf08986bef94b9b47bcc46e6deda02883fa4aa80994167404733469c6b0bcf44bac233bfe7adadf19d8718c69c5bba06d419ed085c8dd318432978a810e84cdf757624a6b7718ee48a18e30d178a6fca0190a682c2e8d19b3485ecf6dbecff77f20bbbdfd509126e95c034f1d33da8021a0602775872aaa0c070373fcfa47337a22c33268fef89da305c73b09854f893ac6a0d64777f8735e321da4b5682d745a071717ba8a6aa3af7d500435ab0e6a4d69bda038ba34e993fa0c3f9dc418d6a2c3da728bf3da7cbdc788e0e5d7aea8f7209b2fa0b2a23c4b9cf4a51b80475054a5260a11efe180ee277d1bf6fd1db47691c05fac80",
    "0xf901b1a03766c0095db3ac22190b3927859bdd17681c7a0a088815a356bc8b68b2c50970a0088dd908e17d45827f051aba0ad5c5774884688383a00e85bd1df4cc0382067ca04b33242af1e013e00f7462bea674e03310a7d01991cec25850acedb74f2066cca01345ad3ab57354d1aadac44bba084363931f30171302e5d1fae16d4c723b5c4fa0011bea5167530c621ab0af62af7a24d59c04c57cb317af55b3f0f42726a37c46a0533f54d65a617fd1beb82e297281ac59afcd6846883452a443f1aca874032680808080a080a539ed77dfc31aaf72676954bdda67fe048f2b592ae01b07dbd87e1ff17c15a0a1232ec8fe4eecbe9fe802b13a425d7117551ba576500c10051f921df1ba8147a08a1094fc803cdbc131187a06223046bcd4d865b5f1b195608b2a509e80004e69a034a0567c7c39af1946167f0ab3e08698b0022e0cdae6aa3c15269e55db437ee1a0c720e8f7e604212720ca2655358a255762cb965a1bee4265237b022d30e0afc1a0f7ba62a85908efbad266464c5947977190359db03bb6ac671f92394026b4dc38a02c625da6aec5bef05183cb11d0af395578e59d1e294df7c5fb599a3825ec175180",
    "0xf8718080a06afbd1c7654b6b9d52014234e510b01bfd6f7c10f22e24471540bfaa46b53775a0d8fefaa3e187233c3385abeca18ae57033dbdff5c4ed62050f5cf75b7523a713a0e9ef0377913d9c0e49370fea3a237326301d428604e51781cab8e4a17477da12808080808080808080808080",
    "0xf85180808080a062f85188be22632dedfa8447cc7fd7548c707322565afab2b484e0e9b879392280a0655feffeb395d62eb4c1580f31633c006686ed789d25b11b9916419a287478ca80808080808080808080",
    "0xf86c9c39649c01070dcbcb013408f88490bf77eca5df2fa52673f498382fe6b84df84b8087038d80f8d26400a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
        ]
    },
    "l2_header": {
        "base_fee_per_gas": "0xa2af3e",
        "extra_data": "0x000000003200000003",
        "logs_bloom": "0xec3bb7f121ddc9da9a295affbe98d85cb60ff3af3a9ac19032bc7febe63f3d11bbfcec7192ff9cf73e9a2a7b1ddaf577b5fcdaf68ff7633f76ff3fa66ebc444825abef3dabffdd6d6ed568ebb5d7c33da3c7ffabf07f7cb1df5fe3d8816ab75dbfd7e6f71ffedf40347ebe22be5e1fbf9739d5ceaf9dbe4f3336f1fdedfb7cd3bb7969fd2d3fd77b597967bd9f0c5d02f7b1d6d9faf5e38efa3ba56f7bf4598a2ec93f8ebdbafcfdfcf8bc4bdbe7a4a03ffbc8c3a3bb8abb0d433bffefddaab5eb96a9fbd1f5def13fb77fd482bf5ef7edf8adcf373bdedaeaeb63eb59192e07f7d73d5de0ff7798bef7a2a6eb524decdfbab5a0e57d3fda7f557dc5b98baf16",
        "parent_hash": "0xfb20e8f10a2e0c3694fe2b87716afcd4ceef8245652e7d2e4a8dbb50af3e4963",
        "receipts_root": "0x0b2a91d9039433c3c4f6746341b7b364eb99700d73c895546cbb278be99fb328",
        "state_root": "0x92415190f48e7cc8f5ff428eb10454b75f061ac31f8219e5ce25b46e1b059737",
        "timestamp": "0x686697bb",
        "transactions_root": "0x7aef4fd1284086c529811688236c82fff54c1e93cd3a432172cdb439744b67d4",
        "withdrawals_root": "0x8e2aa9a38bfebc2ffafaa14c29acf9a5a9aa3bc2fea5195c4e2f1fb2e0e88487",
        "gas_limit": "0x8f0d180",
        "gas_used": "0x3300938",
        "sha3_uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
        "miner": "0x4200000000000000000000000000000000000011",
        "nonce": "0x0000000000000000",
        "number": "0x1ee1d6c",
        "difficulty": "0x0",
        "mix_hash": "0xa067545459cd316f8fb75217ebae6b0a21615d51f4b7f834e9dfec87a8eb8f77",
        "blob_gas_used": "0x0",
        "excess_blob_gas": "0x0",
        "parent_beacon_block_root": "0x0174561516455e244742a6eb9267ec009acb4ec46081aeae5da92d72eb6877b5",
        "requests_hash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    },
    "output_root_proof": {
        "version": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "state_root": "0x92415190f48e7cc8f5ff428eb10454b75f061ac31f8219e5ce25b46e1b059737",
        "message_passer_storage_root": "0x8e2aa9a38bfebc2ffafaa14c29acf9a5a9aa3bc2fea5195c4e2f1fb2e0e88487",
        "latest_block_hash": "0xc7066b0e651a242885e2854e0bb32f2cae89ed12b96cc3547c2f645d2f2617c1"
    }
}"#
            .as_bytes(),
        )
        .unwrap();

        verify_header(&client_state, &header, l1_state_root).unwrap();
    }

    #[test]
    fn test_verify_l2_header_is_related_to_output_root_proof() {
        // Verified against mainnet https://dashboard.tenderly.co/tx/0xddc2095d8d800ddebd22d2717841cb3c7eefa3c76f97316daf6ceb0897a7ab43
        let header = L2Header {
            parent_hash: hex!("fb20e8f10a2e0c3694fe2b87716afcd4ceef8245652e7d2e4a8dbb50af3e4963").into(),
            sha3_uncles: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),
            miner: hex!("4200000000000000000000000000000000000011").into(),
            state_root: hex!("92415190f48e7cc8f5ff428eb10454b75f061ac31f8219e5ce25b46e1b059737").into(),
            transactions_root: hex!(
                "7aef4fd1284086c529811688236c82fff54c1e93cd3a432172cdb439744b67d4"
            ).into(),
            receipts_root: hex!(
                "0b2a91d9039433c3c4f6746341b7b364eb99700d73c895546cbb278be99fb328"
            ).into(),
            logs_bloom: Box::new(hex!("ec3bb7f121ddc9da9a295affbe98d85cb60ff3af3a9ac19032bc7febe63f3d11bbfcec7192ff9cf73e9a2a7b1ddaf577b5fcdaf68ff7633f76ff3fa66ebc444825abef3dabffdd6d6ed568ebb5d7c33da3c7ffabf07f7cb1df5fe3d8816ab75dbfd7e6f71ffedf40347ebe22be5e1fbf9739d5ceaf9dbe4f3336f1fdedfb7cd3bb7969fd2d3fd77b597967bd9f0c5d02f7b1d6d9faf5e38efa3ba56f7bf4598a2ec93f8ebdbafcfdfcf8bc4bdbe7a4a03ffbc8c3a3bb8abb0d433bffefddaab5eb96a9fbd1f5def13fb77fd482bf5ef7edf8adcf373bdedaeaeb63eb59192e07f7d73d5de0ff7798bef7a2a6eb524decdfbab5a0e57d3fda7f557dc5b98baf16").into()),
            difficulty: 0_u64.into(),
            number: 0x1ee1d6c_u64.into(),
            gas_limit: 0x8f0d180,
            gas_used: 0x3300938,
            timestamp: 0x686697bb,
            extra_data: hex!("000000003200000003").into(),
            mix_hash: hex!("a067545459cd316f8fb75217ebae6b0a21615d51f4b7f834e9dfec87a8eb8f77").into(),
            nonce: hex!("0000000000000000").into(),
            base_fee_per_gas: 0xa2af3e_u64.into(),
            withdrawals_root: hex!(
                "8e2aa9a38bfebc2ffafaa14c29acf9a5a9aa3bc2fea5195c4e2f1fb2e0e88487"
            ).into(),
            blob_gas_used: 0,
            excess_blob_gas: 0,
            parent_beacon_block_root: hex!(
                "0174561516455e244742a6eb9267ec009acb4ec46081aeae5da92d72eb6877b5"
            ).into(),
            requests_hash: hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").into(),
        };
        let output_root_proof = OutputRootProof {
            // fixed
            version: hex!("0000000000000000000000000000000000000000000000000000000000000000")
                .into(),
            // l2_header.state_root
            state_root: hex!("92415190f48e7cc8f5ff428eb10454b75f061ac31f8219e5ce25b46e1b059737")
                .into(),
            // L2ToL1MessagePasser storage root on L2 at block l2_header.number
            message_passer_storage_root: hex!(
                "8e2aa9a38bfebc2ffafaa14c29acf9a5a9aa3bc2fea5195c4e2f1fb2e0e88487"
            )
            .into(),
            // hash(l2_header)
            latest_block_hash: hex!(
                "c7066b0e651a242885e2854e0bb32f2cae89ed12b96cc3547c2f645d2f2617c1"
            )
            .into(),
        };

        verify_l2_header_is_related_to_output_root_proof(&output_root_proof, &header).unwrap();
    }
}
